import { TeaDefine } from "../../../kds-base-define/src/TeaDefine"
import { ServerValues } from "../../../kds-base-define/src/ServerConfig"
import { DB } from "../db"
import { Log } from "../log"
import { RpcRoomTea } from "./room"
import { Rpc } from "../rpc"
import { MutexDefine } from "../../../kds-base-define/src/MutexDefine"
import { RpcUserInfo, RpcUserLogin } from "./user"
import { kdutils } from "kdweb-core/lib/utils"
import { TeaCodeID } from "./tea_id_code"
import { TeaService } from "../../../kds-base-define/src/TeaService"
import { MemCaches } from "../cache/MemCaches"
import { UserDefine } from "../../../kds-base-define/src/UserDefine"
import { promises } from "dns"


let dataTablename = "t_tea_data"
let authTablename = "t_tea_auth"
let memberTablename = "t_tea_member"
let templateTablename = "t_tea_template"
let accountTablename = " t_tea_account"
let deskCostTablename = "t_tea_deskcost"

let db = DB.get(ServerValues.dbTea,"tea-get")
let redis = DB.redis
async function getTeaData(h:string,codeOrID:string | number) {
	let teaID = await TeaCodeID.toID(codeOrID)
	if(teaID == null) {
		return null
	}
	let teaData:TeaDefine.TeaData = await redis.hget(dataTablename,teaID.toString(),true)
	return teaData
}

async function getTeaAuth(h:string,teaID:number) {
	let teaAuth:TeaDefine.TeaAuth = await redis.hget(authTablename,teaID.toString(),true)
	return teaAuth
}

async function getTeaMember(h:string,teaID:number) {
	let teaMember:TeaDefine.TeaMember = await redis.hget(memberTablename,teaID.toString(),true)
	if(teaMember) {
		//let friendsArray:TeaDefine.TeaFriend[][] = [teaMember.reqMemberIDs,teaMember.inviteMemberIDs,teaMember.members]
		let friendsArray:TeaDefine.TeaFriend[][] = [teaMember.members]
		let changed = false 
		for(let array of friendsArray) {
			let promises:Promise<UserDefine.LoginData>[] = []
			for(let friend of array) {
				promises.push(MemCaches.loginData.getData({userID:friend.userID}))
			}
			let loginDatas = await Promise.all(promises)
			for(let friend of array) {
				let loginData = loginDatas.find(v=>v.userID == friend.userID)
				if(loginData) {
					friend.nickName = loginData.nickName
					friend.iconUrl = loginData.iconUrl
				} else {
					friend.nickName = "游客" + friend.userID
					friend.iconUrl = "NULL"
				}
			}
		}
		// if(changed) {
		// 	Log.oth.info("[tea-get] teaMember changed teaID = " + teaID)
		// 	updateTeaMember(h,teaMember)
		// }
	}
	return teaMember
}

async function getSimpleTeaMember(h:string,teaID:number) {
	return await redis.hget(memberTablename,teaID.toString(),true)
}

async function refreshTeaMember(h:string,teaID:number) {
	let teaMember:TeaDefine.TeaMember = await redis.hget(memberTablename,teaID.toString(),true)
	if(teaMember) {
		let friendsArray:TeaDefine.TeaFriend[][] = [teaMember.reqMemberIDs,teaMember.inviteMemberIDs,teaMember.members]
		let changed = false 
		for(let array of friendsArray) {
			for(let friend of array) {
				let loginData = await MemCaches.loginData.getData({userID:friend.userID})
				if(loginData) {
					if(friend.nickName != loginData.nickName || 
						friend.iconUrl != loginData.iconUrl) {
						Log.oth.info("[tea-get] teaMember changed teaID = " + teaID + " userID = " + loginData.userID)
						friend.nickName = loginData.nickName
						friend.iconUrl = loginData.iconUrl
						changed = true 
					}
				}
			}
		}
		if(changed) {
			Log.oth.info("[tea-get] teaMember changed teaID = " + teaID)
			updateTeaMember(h,teaMember)
		}

	}
	return teaMember
}

async function getTeaTemplate(h:string,teaID:number) {
	let teaTemplate:TeaDefine.TeaTemplate = await redis.hget(templateTablename,teaID.toString(),true)
	return teaTemplate
}

async function getTeaDeskCost(h:string,teaID:number) {
	let teaCost:TeaDefine.TeaDeskCost = await redis.hget(deskCostTablename,teaID.toString(),true)
	return teaCost 
}

// async function getTeaRoom(h:string,teaID:number) {
// 	let rooms = await RpcRoomTea.get(h,teaID)
// 	let ret:TeaDefine.TeaRoom = {
// 		teaID:teaID,
// 		rooms:rooms
// 	}
// 	return ret
// }

async function getTeaAccount(h:string,teaID:number) {
	let teaAccount:TeaDefine.TeaAccount = await redis.hget(accountTablename,teaID.toString(),true)
	return teaAccount
}

async function getTeaFullData(h:string,teaID:number) {
	let teaData = await getTeaData(h,teaID)
	if(teaData == null) {
		Log.oth.error("[tea-get] getTeaFullData: getTeaData failed teaID = " + teaID)
		return null
	}
	let ret:TeaDefine.TeaFullData = {
		teaID:teaData.teaID,
		teaCode:teaData.teaCode,
		
		data:teaData,
		auth:null,
		member:null,
		template:null,
		account:null,
		room:null,
	}
	ret.auth = await getTeaAuth(h,teaID)
	if(ret.auth == null) {
		Log.oth.error("[tea-get] getTeaFullData: getTeaData failed teaID = " + teaID)
		return null
	}
	ret.member = await getTeaMember(h,teaID)
	if(ret.member == null) {
		Log.oth.error("[tea-get] getTeaFullData: getTeaMember failed teaID = " + teaID)
		return null
	}
	ret.template = await getTeaTemplate(h,teaID)
	if(ret.template == null) {
		Log.oth.error("[tea-get] getTeaFullData: getTeaTemplate failed teaID = " + teaID)
		return null
	}
	ret.account = await getTeaAccount(h,teaID)
	if(ret.account == null) {
		Log.oth.error("[tea-get] getTeaFullData: getTeaAccount failed teaID = " + teaID)
		return null
	}
	// ret.room = await getTeaRoom(h,teaID)
	// if(ret.room == null) {
	// 	Log.oth.error("[tea-get] getTeaFullData: getTeaRoom failed teaID = " + teaID)
	// 	return null
	// }
	return ret 
}

async function getTeaIDbyCode(h:string,teaCode:string) {
	return await TeaCodeID.toID(teaCode)
}

async function getTeaCodeByID(h:string,teaID:number) {	
	return await TeaCodeID.toCode(teaID)

}

let dbTeaCreate = DB.get(ServerValues.dbTea,"tea-create")
async function createTea(h:string,bossUserID:number,teaName?:string) {
	let loginData = await RpcUserLogin.get(h,bossUserID)
	if(loginData == null) {
		return null 
	}
	let teaID:number = await Rpc.center.callException("kds.ids.getId","teaID",800000,1)
	if(teaID == null) {
		return null
	}
	let teaCode:string = await Rpc.center.callException("kds.code.get",6,"teaCode") 
	if(teaCode == null) {
		return null
	}
	
	let bossMember:TeaDefine.TeaFriend = {
		userID:loginData.userID,
		sk:null,

		nickName:loginData.nickName,
		iconUrl:loginData.iconUrl,
		sex:loginData.sex,

		timestamp:kdutils.getMillionSecond(),
		date:kdutils.getFmtMoment("YYYY-MM-DD HH:mm:ss"),

		inviteUserID:null,
	}
	let teaFullData:TeaDefine.TeaFullData = {
		teaID:teaID,
		teaCode:teaCode,
		data: {
			teaID:teaID,
			teaCode:teaCode,

			teaMode:TeaDefine.TeaModeType.Normal,

			teaName:teaName || loginData.nickName,
			
			bossUserID:loginData.userID,
			bossSK:loginData.sk,

			regDate:kdutils.getFmtMoment("YYYY-MM-DD HH:mm:ss"),
			regTimestamp:kdutils.getMillionSecond(),

			cardCount:0,

			status:TeaDefine.TeaStatus.Normal,
		},
		auth: {
			teaID:teaID,
			autoDesk:false,
			allowGuest:false,
			adminAddMember:true,
			adminRemoveMember:true,

			adminOperRoom:true,
			adminOperTemplate:true,
		},
		member: {
			teaID:teaID,
			members:[bossMember],
			admins:[],
			proxys:[],
			groups:[],
			leaderRelations:[],
			reqMemberIDs:[],
			inviteMemberIDs:[],
		},
		template: {
			teaID:teaID,
			items:[],
		},
		account: {
			teaID:teaID,
			users:[],
		},
		cost: {
			teaID:teaID,
			targetItems:[],
		},
		room:null,
	}

	let b = true 
	try {
		await redis.hset(dataTablename,teaID.toString(),teaFullData.data,true) > 0
		await redis.hset(authTablename,teaID.toString(),teaFullData.auth,true) > 0
		await redis.hset(memberTablename,teaID.toString(),teaFullData.member,true) > 0
		await redis.hset(templateTablename,teaID.toString(),teaFullData.template,true) > 0
		await redis.hset(accountTablename,teaID.toString(),teaFullData.account,true) > 0
		await redis.hset(deskCostTablename,teaID.toString(),teaFullData.cost,true) > 0
	} catch(error) {
		Log.oth.error("create tea failed exception ",teaFullData,error)
		b = false 
	}
	if(!b) {
		Log.oth.error("create tea failed when insert userID = " + bossUserID + " teaName = " + teaName)
		redis.hdel(dataTablename,teaID.toString())
		redis.hdel(authTablename,teaID.toString())
		redis.hdel(memberTablename,teaID.toString())
		redis.hdel(templateTablename,teaID.toString())
		redis.hdel(accountTablename,teaID.toString())
		redis.hdel(deskCostTablename,teaID.toString())
		Rpc.center.callException("kds.code.release",teaCode) 
		return null
	}
	await TeaCodeID.createMap(teaCode,teaID)
	return teaFullData
}

async function changeCode(h:string,teaID:number,newTeaCode:string) {
	let teaData:TeaDefine.TeaData = await getTeaData(h,teaID)
	if(teaData == null) {
		return null
	}
	if(await db.getSingle(dataTablename,{teaCode:newTeaCode}) != null) {
		return null 
	}
	let oldCode = teaData.teaCode
	teaData.teaCode = newTeaCode
	let b = await updateTeaData(h,teaData)
	if(!b) {
		return null
	}
	await TeaCodeID.delMap(oldCode,teaData.teaID)
	await TeaCodeID.createMap(teaData.teaCode,teaData.teaID)
	return teaData
}

async function deleteTea(h:string,teaID:number) {
	let teaData = await getTeaData(h,teaID)
	if(teaData == null) {
		return false 
	}
	teaID = teaData.teaID
	await TeaCodeID.delMap(teaData.teaCode,teaData.teaID)

	await redis.hdel(dataTablename,teaID.toString())
	await redis.hdel(authTablename,teaID.toString())
	await redis.hdel(memberTablename,teaID.toString())
	await redis.hdel(templateTablename,teaID.toString())
	await redis.hdel(accountTablename,teaID.toString())
	await removeTeaFromAll(h,teaID)
	return true 
}

export let RpcTea = {
	id:getTeaIDbyCode,
	code:getTeaCodeByID,

	create:createTea,
	changeCode:changeCode,

	delete:deleteTea,

	refreshMemeber:refreshTeaMember,
}

export let RpcTeaGet = {
	data:getTeaData,
	auth:getTeaAuth,
	member:getTeaMember,
	simpleMember:getSimpleTeaMember,
	template:getTeaTemplate,
	account:getTeaAccount,
	//room:getTeaRoom,
	cost:getTeaDeskCost,

	full:getTeaFullData,
}


async function updateTeaData(h:string,teaData:TeaDefine.TeaData) {
	await redis.hset(dataTablename,teaData.teaID.toString(),teaData,true)
	return true 
}

async function updateTeaAuth(h:string,teaAuth:TeaDefine.TeaAuth) {
	await redis.hset(authTablename,teaAuth.teaID.toString(),teaAuth,true)
	return true 
}

async function updateTeaMember(h:string,teaMember:TeaDefine.TeaMember) {
	await redis.hset(memberTablename,teaMember.teaID.toString(),teaMember,true)
	return true 
}

async function updateTeaTemplate(h:string,teaTemplate:TeaDefine.TeaTemplate) {
	await redis.hset(templateTablename,teaTemplate.teaID.toString(),teaTemplate,true)
	return true 
}

async function updateTeaAccount(h:string,teaAccount:TeaDefine.TeaAccount) {
	await redis.hset(accountTablename,teaAccount.teaID.toString(),teaAccount,true)
	return true 
}

async function updateTeaDeskCost(h:string,teaDeskCost:TeaDefine.TeaDeskCost) {
	await redis.hset(deskCostTablename,teaDeskCost.teaID.toString(),teaDeskCost,true)
	return true 
}

export let RpcTeaUpdate = {
	data:updateTeaData,
	auth:updateTeaAuth,
	member:updateTeaMember,
	template:updateTeaTemplate,
	account:updateTeaAccount,
	cost:updateTeaDeskCost,
}

let userTableName = "t_tea_user"
type userPOData = {
	teaIDs:number[],
}
async function addTeaToUser(h:string,userID:number,teaID:number) {
	let data:userPOData = await redis.hget(userTableName,userID.toString(),true)
	if(data == null) {
		data = {
			teaIDs:[]
		}
	}
	if(data.teaIDs.includes(teaID)) {
		return true 
	}
	data.teaIDs.push(teaID)
	await redis.hset(userTableName,userID.toString(),data,true)
	return true 
}

async function removeTeaFromUser(h:string,userID:number,teaID:number) {
	let data:userPOData = await redis.hget(userTableName,userID.toString(),true)
	if(data == null) {
		return true 
	}
	let idx = data.teaIDs.indexOf(teaID)
	if(idx < 0) {
		return true 
	}
	data.teaIDs.splice(idx,1)
	await redis.hset(userTableName,userID.toString(),data,true)
	return true 
}

async function getAllTeaIDs(h:string,userID:number) {
	let data:userPOData = await redis.hget(userTableName,userID.toString(),true)
	if(data) {
		return data.teaIDs
	}
	return []
}

async function removeTeaFromAll(h:string,teaID:number) {
	let datas = await redis.hgetall(userTableName,true)
	for(let key of Object.keys(datas)) {
		let userID = Number.parseInt(key)
		let data:userPOData = datas[key]
		if(data.teaIDs.includes(teaID)) {
			removeTeaFromUser(h,userID,teaID)
		}
	}
	return true 
}

export let RpcTeaUser = {
	add:addTeaToUser,
	remove:removeTeaFromUser,
	getAll:getAllTeaIDs,
	removeTea:removeTeaFromAll
}

let configTableName = "t_tea_service_config"
async function getTeaConfig(h:string) {
	return await redis.get(configTableName,true)
}

async function setTeaConfig(h:string,config:TeaService.Config) {
	await redis.set(configTableName,config,true)
}


let templateNameTablename = "t_tea_template_name"
async function setTemplateName(h:string,templateID:number,name:string) {
	await redis.hset(templateNameTablename,templateID.toString(),name)
}

async function getTemplateName(h:string,templateID:number) {
	return redis.hget(templateNameTablename,templateID.toString())
}

export let RpcTeaService = {
	getConfig:getTeaConfig,
	setConfig:setTeaConfig,

	setTemplateName,
	getTemplateName,
}
